package org.destinyshine.cricket.deploy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

import javax.xml.bind.JAXBException;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.destinyshine.cricket.container.ServletWrapper;
import org.destinyshine.cricket.container.WebApplicationContainer;
import org.destinyshine.cricket.container.WebApplicationContext;
import org.destinyshine.cricket.context.description.ContextParam;
import org.destinyshine.cricket.jaxbmodel.*;
import org.destinyshine.cricket.utils.MyCollectionUtils;

/**
 * Created by destinyliu on 2016/2/28.
 */
public class WebAppDeployHelper {

    private static final Logger logger = LogManager.getLogger();
    private final File contextBase;

    private WebApplicationContainer container;

    private WebApplicationContext applicationContext;


    public WebAppDeployHelper(WebApplicationContext applicationContext) throws FileNotFoundException, JAXBException {
        this.applicationContext = applicationContext;
        this.container = applicationContext.getContainer();
        this.contextBase = applicationContext.getContextBase();
    }

    /**
     * 根据web部署描述符（web.xml）初始化context.
     * @throws FileNotFoundException
     * @throws JAXBException
     */
    public void parseWebDescriptor() throws FileNotFoundException, JAXBException {
        FileInputStream webxmlis = new FileInputStream(new File(contextBase, "/WEB-INF/web.xml"));

        WebAppElement webAppElement = WebXMLParser.parse(webxmlis);

        applicationContext.setDisplayName(webAppElement.getDisplayName());

        resolveClassPath();
        resolveContextParams(webAppElement);
        resolveListeners(webAppElement);
        resolveFilters(webAppElement);
        resolveServlets(webAppElement);
    }

    private void resolveClassPath() {
        ArrayList<URL> libs = new ArrayList<>();

        File libDir = new File(contextBase, "WEB-INF/lib");

        applicationContext.addClassPathEntrysDir(libDir);

        applicationContext.addClassPathEntry(new File(contextBase, "/WEB-INF/classes/"));
    }

    private void resolveContextParams(WebAppElement webAppElement) {
        if(CollectionUtils.isNotEmpty(webAppElement.getContextParams())) {
            return;
        }

        for(ContextParamElement paramEle:webAppElement.getContextParams()) {
            Map<String, String> contextParams = new LinkedHashMap<>();
            contextParams.put(paramEle.getParamName(), paramEle.getParamValue());
            applicationContext.setContextParams(contextParams);
        }

    }

    private void resolveListeners(WebAppElement webAppElement) {
        if(CollectionUtils.isEmpty(webAppElement.getListeners())) {
            return;
        }
        for (ListenerElement listenerEle : webAppElement.getListeners()){
            applicationContext.addListener(listenerEle.getListenerClass());
        }
    }

    private void resolveServlets(WebAppElement webAppElement) throws FileNotFoundException, JAXBException {
        if(CollectionUtils.isEmpty(webAppElement.getServlets())) {
            return;
        }
        for (ServletElement servletEle : webAppElement.getServlets()) {
            try {
                List<InitParam> initParams = servletEle.getInitParams();
                Map<String, String> initParamMap = new HashMap<>();
                if (CollectionUtils.isNotEmpty(initParams)) {
                    for (InitParam initParam : initParams) {
                        initParamMap.put(initParam.getParaName(), initParam.getParamValue());
                    }
                }
                applicationContext.addServlet(
                        servletEle.getServletName(),
                        servletEle.getServletClass(),
                        initParamMap,
                        servletEle.getLoadOnStartup()
                );
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }

        for (ServletMappingElement sme : webAppElement.getServletMappings()) {
            applicationContext.addServletMapping(sme.getServletName(), sme.getUrlPattern());
        }

    }

    private void resolveFilters(WebAppElement webAppElement) {
        if(CollectionUtils.isEmpty(webAppElement.getFilters())) {
        return;
    }
        for (FilterElement filterEle : webAppElement.getFilters()) {
            try {
                applicationContext.addFilter(filterEle.getFilterName(), filterEle.getFilterClass());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }

        for (FilterMappingElement fme : webAppElement.getFilterMappings()) {
            applicationContext.addFilterMapping(fme.getFilterName(), fme.getUrlPattern());
        }
    }

}
